// 配置模块
// 解析和管理同步配置

use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::path::PathBuf;

/// 同步配置
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct SyncConfig {
    /// 调度配置
    pub schedule: ScheduleConfig,
    /// 数据库配置
    pub database: DatabaseConfig,
    /// 数据源配置列表
    pub sources: Vec<DataSource>,
    /// 重试配置
    pub retry: RetryConfig,
    /// 日志配置
    pub logging: LoggingConfig,
}

/// 调度配置
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ScheduleConfig {
    /// 每天记录数据的时间 (HH:MM:SS)
    pub daily_record_time: String,
    /// 每天检查数据的时间 (HH:MM:SS)
    pub daily_check_time: String,
}

/// 数据库配置
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct DatabaseConfig {
    /// 数据库路径
    pub path: String,
    /// 命名空间
    pub namespace: String,
    /// 数据库名
    pub database: String,
}

/// 数据源配置
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct DataSource {
    /// 数据源名称
    pub name: String,
    /// 描述
    pub description: String,
    /// API 函数名
    pub api_function: String,
    /// 是否启用
    pub enabled: bool,
    /// 同步类型: snapshot, daily, historical
    pub sync_type: String,
    /// 目标表名
    pub table: String,
    /// 参数
    #[serde(default)]
    pub parameters: HashMap<String, String>,
}

/// 重试配置
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct RetryConfig {
    /// 最大重试次数
    pub max_retries: u32,
    /// 重试延迟（秒）
    pub retry_delay_seconds: u64,
    /// 超时时间（秒）
    pub timeout_seconds: u64,
}

/// 日志配置
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct LoggingConfig {
    /// 日志级别
    pub level: String,
    /// 日志文件路径
    pub log_file: String,
}

impl SyncConfig {
    /// 从文件加载配置
    pub fn from_file(path: &str) -> Result<Self> {
        let content = std::fs::read_to_string(path)
            .context(format!("读取配置文件失败: {}", path))?;
        
        let config: SyncConfig = toml::from_str(&content)
            .context("解析配置文件失败")?;
        
        Ok(config)
    }
    
    /// 获取启用的数据源
    pub fn enabled_sources(&self) -> Vec<&DataSource> {
        self.sources.iter().filter(|s| s.enabled).collect()
    }
    
    /// 获取快照类型的数据源
    pub fn snapshot_sources(&self) -> Vec<&DataSource> {
        self.sources
            .iter()
            .filter(|s| s.enabled && s.sync_type == "snapshot")
            .collect()
    }
    
    /// 获取每日类型的数据源
    pub fn daily_sources(&self) -> Vec<&DataSource> {
        self.sources
            .iter()
            .filter(|s| s.enabled && s.sync_type == "daily")
            .collect()
    }
    
    /// 转换为数据库配置
    pub fn to_db_config(&self) -> akoption::db::DbConfig {
        akoption::db::DbConfig::new(
            PathBuf::from(&self.database.path),
            &self.database.namespace,
            &self.database.database,
        )
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_parse_config() {
        let toml_str = r#"
[schedule]
daily_record_time = "15:30:00"
daily_check_time = "08:00:00"

[database]
path = "./data/test.db"
namespace = "test"
database = "options"

[[sources]]
name = "test_source"
description = "Test"
api_function = "test_func"
enabled = true
sync_type = "snapshot"
table = "test_table"

[retry]
max_retries = 3
retry_delay_seconds = 5
timeout_seconds = 30

[logging]
level = "info"
log_file = "./test.log"
"#;
        
        let config: SyncConfig = toml::from_str(toml_str).unwrap();
        assert_eq!(config.schedule.daily_record_time, "15:30:00");
        assert_eq!(config.sources.len(), 1);
        assert_eq!(config.sources[0].name, "test_source");
    }
    
    #[test]
    fn test_enabled_sources() {
        let toml_str = r#"
[schedule]
daily_record_time = "15:30:00"
daily_check_time = "08:00:00"

[database]
path = "./data/test.db"
namespace = "test"
database = "options"

[[sources]]
name = "enabled_source"
description = "Enabled"
api_function = "test_func"
enabled = true
sync_type = "snapshot"
table = "test_table"

[[sources]]
name = "disabled_source"
description = "Disabled"
api_function = "test_func2"
enabled = false
sync_type = "snapshot"
table = "test_table2"

[retry]
max_retries = 3
retry_delay_seconds = 5
timeout_seconds = 30

[logging]
level = "info"
log_file = "./test.log"
"#;
        
        let config: SyncConfig = toml::from_str(toml_str).unwrap();
        let enabled = config.enabled_sources();
        assert_eq!(enabled.len(), 1);
        assert_eq!(enabled[0].name, "enabled_source");
    }
    
    #[test]
    fn test_retry_config() {
        let config = RetryConfig {
            max_retries: 5,
            retry_delay_seconds: 10,
            timeout_seconds: 60,
        };
        
        assert_eq!(config.max_retries, 5);
        assert_eq!(config.retry_delay_seconds, 10);
        assert_eq!(config.timeout_seconds, 60);
    }
    
    #[test]
    fn test_data_source_with_parameters() {
        let toml_str = r#"
[schedule]
daily_record_time = "15:30:00"
daily_check_time = "08:00:00"

[database]
path = "./data/test.db"
namespace = "test"
database = "options"

[[sources]]
name = "param_source"
description = "With Parameters"
api_function = "test_func"
enabled = true
sync_type = "snapshot"
table = "test_table"

[sources.parameters]
symbol = "50ETF"
date = "20241029"

[retry]
max_retries = 3
retry_delay_seconds = 5
timeout_seconds = 30

[logging]
level = "info"
log_file = "./test.log"
"#;
        
        let config: SyncConfig = toml::from_str(toml_str).unwrap();
        assert_eq!(config.sources[0].parameters.get("symbol").and_then(|v| Some(v.as_str())), Some("50ETF"));
        assert_eq!(config.sources[0].parameters.get("date").and_then(|v| Some(v.as_str())), Some("20241029"));
    }
}
